#include "widget.h"

#define TIMEOUT 100

float vertices[] = {
    // positions          // normals           // texture coords
    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
    0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 0.0f,
    0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
    0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f, 0.0f,

    -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,
    0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
    0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
    -0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,   0.0f, 0.0f,

    -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
    -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
    -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
    -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

    0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
    0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
    0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

    -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,
    0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 1.0f,
    0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
    0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
    -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 0.0f,
    -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f, 1.0f,

    -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f,
    0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 1.0f,
    0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 1.0f
};
QVector3D cubePositions[] = {
    QVector3D( 0.0f, 0.0f, 0.0f),
    QVector3D( 2.0f, 5.0f, -15.0f),
    QVector3D(-1.5f, -2.2f, -2.5f),
    QVector3D(-3.8f, -2.0f, -12.3f),
    QVector3D( 2.4f, -0.4f, -3.5f),
    QVector3D(-1.7f, 3.0f, -7.5f),
    QVector3D( 1.3f, -2.0f, -2.5f),
    QVector3D( 1.5f, 2.0f, -2.5f),
    QVector3D( 1.5f, 0.2f, -1.5f),
    QVector3D(-1.3f, 1.0f, -1.5f)
};

MyGLWidget::MyGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{
    m_camera.Position = QVector3D(0.0,0.0,5.0);

    m_timer = new QTimer(this);
    connect(m_timer,&QTimer::timeout,this,[&]
    {
        update();
    });
    m_timer->start(TIMEOUT);
    m_time.start();
}

MyGLWidget::~MyGLWidget()
{
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
}

void MyGLWidget::initializeGL()
{
    initializeOpenGLFunctions(); // 初始化 OpenGL 函数

    //创建、绑定VAO
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    //创建、绑定VBO + 填充数据
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    //设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    //纹理坐标
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    //解绑缓冲区和 VAO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    shader = new Shader(":/shader/shader.vert", ":/shader/shader.frag");

    //创建、绑定纹理
    texture1 = loadTexture(":/img/container2.png", true);
#if 1
    texture2 = loadTexture(":/img/container2_specular.png");

    // 绑定着色器程序
    //shader->bind();
    // 设置纹理采样器
    //shader->setUniformValue("texture1", 0); // 设置采样器 texture1 到纹理单元 0
    //shader->setUniformValue("texture2", 1); // 设置采样器 texture2 到纹理单元 1
#endif
}

void MyGLWidget::paintGL()
{
#if 0
    QVector3D cameraPos(0.0f, 0.0f, 3.0f);//摄像机位置
    QVector3D cameraTarget = QVector3D(0.0f, 0.0f, 0.0f);
    QVector3D cameraDirection = QVector3D(cameraPos - cameraTarget);//方向向量
    cameraDirection.normalize();
    QVector3D up = QVector3D(0.0f, 1.0f, 0.0f);
    QVector3D cameraRight = QVector3D::crossProduct(up, cameraDirection);//右轴
    cameraRight.normalize();
    QVector3D cameraUp = QVector3D::crossProduct(cameraDirection, cameraRight);//上轴
#endif

    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色缓冲区

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture1);
#if 1
    glActiveTexture(GL_TEXTURE1); // 激活纹理单元 1
    glBindTexture(GL_TEXTURE_2D, texture2); // 绑定第二个纹理
#endif

    QMatrix4x4 model, view, projection;
    projection.setToIdentity();
    projection.perspective(m_camera.Zoom, (float)width() / (float)height(), 0.1f, 100.0f);

    view = m_camera.GetViewMatrix();

    shader->bind();
    glBindVertexArray(VAO);

    shader->use();
    shader->setUniformValue("light.position", 1.2f, 1.0f, 2.0f);
    shader->setUniformValue("viewPos", m_camera.Position);

    // light properties
    shader->setUniformValue("light.ambient", 0.4f, 0.4f, 0.4f);
    shader->setUniformValue("light.diffuse", 0.9f, 0.9f, 0.9f);
    shader->setUniformValue("light.specular", 1.0f, 1.0f, 1.0f);
    shader->setUniformValue("light.constant",  1.0f);
    shader->setUniformValue("light.linear",    0.09f);
    shader->setUniformValue("light.quadratic", 0.032f);

    // material properties
    shader->setUniformValue("material.shininess", 32.0f);


    shader->setUniformValue("view", view);
    shader->setUniformValue("projection", projection);
    int i = 0;
    for (const auto& pos : cubePositions)
    {
        model.setToIdentity();
        model.translate(pos);
        float angle = 20.0f * i;
        model.rotate(angle, 1.0f, 0.3f, 0.5f);
        shader->setUniformValue("model", model);

        glDrawArrays(GL_TRIANGLES, 0, 36);
        //glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        i++;
    }

    glBindVertexArray(0);
}

void MyGLWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h); // 设置视口大小
}

unsigned int MyGLWidget::loadTexture(const char *fileName, bool alpha)
{
    unsigned int texture;
    glGenTextures(1, &texture); // 生成纹理 ID
    glBindTexture(GL_TEXTURE_2D, texture); // 绑定纹理

    // 设置纹理参数
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#if 0
    // 加载图片并转换为 OpenGL 格式
    QImage image;
    if (!image.load(fileName))
    {
        qWarning() << "Failed to load texture image";
        return 0;
    }
    image = QGLWidget::convertToGLFormat(image); // 转换为 OpenGL 格式
    unsigned char *data = image.bits();
    // 生成纹理
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D); // 生成多级渐远纹理
#else

    QFile file(fileName);
    file.copy(file.fileName(), QFileInfo(file).fileName());

    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
    unsigned char *data = stbi_load(QFileInfo(file).fileName().toStdString().c_str(), &width, &height, &nrChannels, 0);
    if (data)//awesomeface  container
    {
        if(alpha)
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        else
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture1" << std::endl;
    }
    stbi_image_free(data);
#endif
    return texture;
}

void MyGLWidget::keyPressEvent(QKeyEvent *event)
{
#if 0
    float deltatime=TIMEOUT / 1000.0;
    switch(event->key())
    {
    case Qt::Key_Up:ratio += 0.1;break;
    case Qt::Key_Down:ratio -= 0.1;break;
    case Qt::Key_W: m_camera.ProcessKeyboard(FORWARD,deltatime);break;
    case Qt::Key_S: m_camera.ProcessKeyboard(BACKWARD,deltatime);break;
    case Qt::Key_D: m_camera.ProcessKeyboard(RIGHT,deltatime);break;
    case Qt::Key_A: m_camera.ProcessKeyboard(LEFT,deltatime);break;
    }

    if(ratio > 1) ratio = 1;
    if(ratio < 0) ratio = 0;

    makeCurrent();
    shader->bind();
    shader->setUniformValue("ratio",ratio);
    update();
    doneCurrent();
#endif
}

void MyGLWidget::mouseMoveEvent(QMouseEvent *event)
{
#if 0
    qDebug() << "mouseMoveEvent";
    static QPoint lastPos(width()/2,height()/2);
    auto currentPos=event->pos();
    deltaPos=currentPos-lastPos;
    lastPos=currentPos;

    m_camera.ProcessMouseMovement(deltaPos.x(),-deltaPos.y());
    update();
#endif
}

void MyGLWidget::wheelEvent(QWheelEvent *event)
{
    qDebug() << "wheelEvent";
    //m_camera.ProcessMouseScroll(event->angleDelta().y()/120);
    update();
}
